package {
	import flash.display.Sprite;
	
	import vue.Cube3D;
	import vue.Objet3D;
	import vue.ObjetDecore3D;
	
	public class Afficheur extends Sprite
	{
		public static function process(filename:String):void
		{
			var sceneComplete:Array = Parseur.getObjects(filename);

			for each(var objet:* in sceneComplete)
			{
				tableau1:Array= Afficheur.transformation1(objet);
				tableau2:Array= Afficheur.transformation2(tableau1,tableau1[0]);

				objet3D:Objet3D = new ObjetDecore3D();

				for(i:Number=0; i< tableau.length; i++) {

					objet3D = new Cube(objet3D,
								tableau1[i].getX(),
								tableau1[i].getY(),
								tableau1[i].getZ(),
								tableau2[i][1],
								tableau2[i][2],
								tableau2[i][3]);
				}
				addChild(objet3D);
			}
			
		}


		// Cette fonction prend un objet et renvoit la matrice de décalage
		// de chaque élément par rapport à un autre (n'importe lequel
		// du moment qu'ils soient reliés )
		public static function transformation1(objet:Objet):Array
		{
			elements:Array= objet.getElements();
			resultat:Array= new Array();

			var x:Number=0;
			var y:Number=0;
			var z:Number=0;

			//TODO Ajouter un test pour éviter de faire un graphe non-connexe
			for(i:Number=0; i<elements.length; i++)
			{
				element1:Element= elements[i];

				// On part du principe qu'un élément a au moins une jointure
				// un element a forcément au moins une jointure
				jointure1:Jointure= element.getJointure(0);
				jointure2:Jointure= jointure1.getJointure(0);
				element2:Element= jointure2.getElement(0);

				x= jointure1.getX()-jointure2.getX();
				y= jointure1.getY()-jointure2.getY();
				z= jointure1.getZ()-jointure2.getZ();

				resultat.push(new Array(element1,element2,x,y,z))
			}

			return resultat;
		}

/*
		public static function transformation2(tableau:Array,element:Element):Array
		{
			relatives:Array= new Array();
			absolues:Array= new Array();

			var x:Number=0;
			var y:Number=0;
			var z:Number=0;
			var elem:Element=null;

			for(i:Number=0; i<tableau.length; i++)
			{
				x= tableau[i][2];
				y= tableau[i][3];
				z= tableau[i][4];
				elem=tableau[i][0];

				if((tableau[i][1] == element) && (absolues.length == 0))
				{
					absolues.push(elem,x,y,z);
				} 
				else {
					if(tableau[i][1] == element)
					{
						relatives.push(elem,x+absolues[1],y+absolues[2],z+absolues[3]);
					}
				}
			}
		}
*/

		public static function transformation2(tableau:Array,element:Element):Array {

			retour:Array = new Array();
			resultat:Array= new Array();

			var x:Number;
			var y:Number;
			var z:Number;
			
			// je cherche les éléments reliés à "element"
			for(i:Number=0; i<tableau.length; i++)
			{
				if(element == tableau[i][1])
				{

					// Si on n'a pas encore trouvé de ligne correspondante
					if(resultat.length==0)
					{
						// le premier garde les coordonnées
						resultat= tableau.splice(i,1);
						resultat= resultat[0];
					}
					else {
						// tous les suivants prennent
						// comme objet relatif le premier
						// et prennent pour coordonnées les leurs - celles du premier			
						x= tableau[i][2]-resultat[2];
						y= tableau[i][3]-resultat[3];
						z= tableau[i][4]-resultat[4];

						tableau[i]= new Array(tableau[i][0],resultat[0],x,y,z);
					}
				}
			}


			retour.push(resultat);
			retour.concat(Afficheur.transformation2(tableau,resultat[0]));

			return retour;
		}

		public static function lineariser(objet:Objet)
		{

			// Je suis sur un élément
			// je ne m'intérresse qu'aux jointures utilisées et à leurs coordonnées
			// On conserve les coordonnées de la première jointure
			// S'il y a d'autres jointures, on décale leurs coordonnées en prenant comme offset les coordonnées de la jointure précédente


			// elems=objet.getElements()
			// Je prend un élément et je regarde quelles jointures sont utilisées
			// Foreach(elems.jointures as jointure)
			// {si jointure.connections.length!=0) jointures.append( e.connections)}

			// Pour chaque jointure utilisée je regarde l'élément auquel il appartient.
			// L'un après l'autre je les positionne 
		}

		// Cette fonction génère un objet3D à partir d'une structure
		// de donnée de type "Objet"
		// Nota bene: un objet peut être représenter comme un graphe
		public static function objetToObjet3D(e:Element,j:Jointure,elementsATraiter:Array=new Array()):Objet3D
		{
			// S'il n'y a plus qu'un élément à traiter
			// On renvoit l'élément 3D le plus profond dans l'encapsulation
			// (Celui qui décore un objet vide)
			if(elementsAVisiter.length==1) 
			{
				var element:Element= elements.pop();
				return new Cube3D(new ObjetDecore3D(),e.getHeight(),e.getWidth(),e.getDepth(),0,0,0);
			}

			// listes des jointures de l'élément
			var jointures:Array=e.getJointures();

			// On initialise l'objet 3D (vide)
			var objet3d:Objet3D= new ObjetDecore3D();

			// On initialise le tableau d'exploration
			// Ce dernier sert à savoir si un élément a 
			// déjà été traité
			var elementTraites:Array= new Array();

			return new Cube3D(Afficheur.objetToObjet3D(?),e.getHeight(),e.getWidth,e.getDepth(),j.getX(),j.getY(),j.getZ());
		}

		// Cette fonction parcourt récurcivement un objet et retourne l'objet3D correspondant
		// La fonction prend en paramètre l'élément à prendre comme point de départ
		// et une matrice donnant 
		public static function elementToObjet3D(e:Element,elementsATraiter:Array):Array
		{
			if(elementsATraiter.length == 1) {
				var x:Number= elementsATraiter[0][1];
				var y:Number= elementsATraiter[0][2];
				var z:Number= elementsATraiter[0][3];
				

				return new Cube(new ObjetDecore3D(),x,y,z)
			}
		}
	}
}
